package com.jdk.demo.fileChannel;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

// 其实在调用FileChannel的write方法时，操作系统为了运行的效率，先是把那些将要保存到硬盘的数据暂时放入操作系统内核的缓存中，以减少硬盘的读写次数，
// 然后在某一个时间点再将内核缓存中的数据批量同步到硬盘中，但同步的时间却是由操作系统决定的，因为时间是未知的，这时就不能让操作系统来决定，所以要
// 显式的调用force方法来强制进行同步，这样做的目的是防止在系统崩溃或者断电时缓存中的数据丢失。但是force方法并不能完全保证数据不丢失，如正在执行
// force方法时出现断电情况，那么硬盘上的数据有可能就不是完整的，而且由于断电的原因导致内核缓存中的数据也丢失了，最终造成的结果就是force方法执行
// 了，数据也有可能丢失。既然调用该方法也有可能造成数据丢失，那么该方法的最终目的是什么呢？其实force方法的最终目的是尽最大努力减少数据的丢失。例如
// 内核缓冲中有10kb的数据需要同步，那么可以每2kb就执行1次force方法来同步到硬盘上，也就不至于缓存中有10kb数据，在突然断电时，这10kb数据全部丢失的
// 情况发生，因此，force方法的目的是尽可能少地丢失数据，而不是保证完全不丢失数据

// 参数metaData的作用：如果传入值为true，则需要此方法强制对要写入存储设备的文件内容和元数据进行更改，否则只需要强行写入内容更改。
// 此方法需要依赖于底层操作系统的支持，在linux所使用的glibc库的2.17版本中，这两个方法的作用是一样的，因为fdatasync调用的就是fsync方法。
// 如果java代码在linux系统中进行测试，无论传入的是false还是true，都会更新文件的元数据，因为最终调用的都是fsync方法。
public class ForceDemo {

	// force方法的性能
	public static void main(String[] args) throws Exception {
		FileOutputStream fileA = new FileOutputStream(new File("m.txt"));
		FileChannel fileChannelA = fileA.getChannel();
		long beginTime = System.currentTimeMillis();
		for(int i=0; i<5000; i++){
			fileChannelA.write(ByteBuffer.wrap("abcde".getBytes()));
			// 是否force，性能会差出几个数量级
			// fileChannelA.force(false);
		}
		long end = System.currentTimeMillis();
		System.out.println(end - beginTime);
		fileA.close();
		fileChannelA.close();
	}
	
}
